package psim;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.SAXException;

/**
 * Trida, ktera zapouzdruje pole castic a operace s nimi
 * Je to rodicovska trida, jsou od ni odvozene tridy PtcsMulti a PtcsSingle
 *
 * @author Tomas Drimal
 */
public abstract class PtcsBase {
    //pole castic
    public ArrayList<Particle> partcs = new ArrayList<Particle>();
    // pole dvou castic, z duvodu volani metody podle jmena
    Class pts[] = {Particle.class,Particle.class};

    /**
     * Metoda, která volá LoadFromFile(String Filename), vpodstate ji
     * zapouzdruje. Z duvodu nasledneho dedeni teto PtcsBase tridy.
     * @param filename - jméno csv souboru s částicemi
     * @return true, pokud je vse v pořádku, jinak vraci false
     * @see #LoadFromFile(String Filename) LoadFromFile(String Filename)
     */
    public boolean LoadFromFile(String filename) {
        if (LoadFrFile(filename)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Metoda, ktera nacte do pole castice ze souboru
     * @param Filename - jméno csv souboru s casticemi
     * @return true, pokud je vse v pořádku, jinak vraci false
     */
    public boolean LoadFrFile(String Filename) {

        //smazani pole castic
        partcs.clear();
        //smazani pole s historii
        Main.PtcsHist.clear();
        FileAccess.LoadFromFile(Filename);
        //Inicializace simulace
        for (int i = 0; i < Main.particles.size(); i++) {
            //x-ova a y-ova souradnice aktualni polohy castice (dano stredem)
            int x = (int) (partcs.get(i).x / Main.scale_x * psim.Main.CLIENT_WIDTH_PX);
            int y = (int) (partcs.get(i).y / Main.scale_y * psim.Main.CLIENT_HEIGHT_PX);

            int pole[] = {x, y, (int) partcs.get(i).d / 2, x, y};
            Main.PtcsHist.add(pole);
        }
        Main.cykly = 0;
        return true;
    }
    /*
     * Metoda, ktera ulozi castice i s nastavenim simulace
     * do souboru typu pts
     */
    public void SaveToFile(String Filename) {
        try {
            FileAccess.SaveToFile(Filename);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(PtcsBase.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PtcsBase.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SAXException ex) {
            Logger.getLogger(PtcsBase.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Metoda prida instanci Particle na konec pole
     * @param pts Prticle, ktere ma byt pridano
     */
    public void add(Particle pt) {
        this.partcs.add(pt);
    }

    /**
     * Metoda vrati Particle na pozici i
     * @param i index pozadovane instance Particle
     * @return pozadovanou castici na indexu i
     */
    public Particle get(int i) {
        return this.partcs.get(i);
    }

    /**
     * Metoda pro zjisteni poctu castic v poli
     * @return Pocet castic v poli
     */
    public int size() {
        return this.partcs.size();
    }

    /**
     * Abstraktní metoda, jeji telo je ve tridach PtcsSingle a PtcsMulti
     */
    public abstract void chPos();

    /**
     * Metoda, ktera zavola metodu Patricle.changePos v intervalu from-to
     * @param from zacatek intervalu
     * @param to konec intervalu
     */
    public void chPosFT(int from, int to) throws NoSuchMethodException,
            IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        for (int i = from; i < to; i++) {
            for (int j = i + 1; j < this.partcs.size(); j++) {
                Method mthd=PtcCompute.class.getMethod(Main.mthdName,pts);
                mthd.invoke(null,partcs.get(i), partcs.get(j));
            }
            Main.particles.get(i).changePos();
        }

    }

    /**
     * metoda, ktera ulozi hodnoty poloh a rychlosti z predchoziho (soucasneho)
     * kroku
     */
    public void saveNew() {
        for (Particle pt : partcs) {
            pt.saveVals();
        }
    }
    /*
     * Metoda spusteni simulace
     */
    public void startSim() {
        while (true) {
            if (Main.simulation) {
                if (Main.nrOfSteps == -1) {
                    chPos();
                }
                if (Main.nrOfSteps == 0) {
                    Main.simulation = false;
                    Main.nrOfSteps = -1;
                    gui.Gui.btnPlay.setEnabled(true);
                    gui.Gui.btnPlay0.setEnabled(true);
                }
                if (Main.nrOfSteps > 0) {
                    for (long i = Main.nrOfSteps; i > 0; i--) {
                        chPos();
                        Main.nrOfSteps--;

                    }
                }
            }

        }
    }
    /*
     * Metoda, ktera ulozi castice do souboru typu csv
     */
    public void toCsvFile(File file)
            throws FileNotFoundException, IOException {
        ArrayList<String> buff = new ArrayList<String>();
        for (Particle pt : partcs) {
            buff.add(pt.toCsvLine());
        }
        FileAccess.SaveToCSV(file, buff);
    }
}
